/*
 * @Author: xiaosihan 
 * @Date: 2023-08-25 21:54:17 
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2024-07-06 16:29:44
 */

import { fabric } from "fabric";
import { IImageOptions } from "fabric/fabric-impl";
import { Color } from "three";

// 画布遮罩
export default class FabricMark extends fabric.Image {


    constructor(element: string | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement, options?: Partial<IImageOptions>) {
        super(element, options);
    }

    markColor = "#000000";

    originX = "center";

    originY = "center";

    left = 2048;

    top = 2048;

    width = 4096;

    height = 4096;

    //uv轮廓图的边厂单位mm
    sideLength = 500;

    globalCompositeOperation = "destination-over";

    // 通过svg设置遮罩
    async setvPolygonBySvg(svgUrl: string) {
        if (!svgUrl) {
            return;
        }

        await new Promise<void>((resolve, reject) => {
            fetch(svgUrl)
                .then(response => response.text())
                .then(svgText => {
                    const color = new Color();
                    const colors = svgText.match(/#[a-zA-Z\d]{6}/g) || [];
                    for (let c of colors) {
                        color.set(c);
                        if (color.r > (color.g + 0.5) && color.r > (color.b + 0.5)) {
                            svgText = svgText.replaceAll(c, `${c};display: none;`);
                        } else if (color.r < 0.1 && color.g < 0.1 && color.b < 0.1) {
                            svgText = svgText.replaceAll(c, `${c};fill:${this.markColor};`);
                        }
                    }

                    //路径转多边形
                    // 正则表达式模式，用于匹配路径数据
                    const pathRegex = / d="([^"]+)"/;

                    // 提取路径数据
                    const match = svgText.match(pathRegex) || [];
                    if (match.length) {
                        let pathData = match[1] || "";
                        const Mpath = pathData.split("M");
                        svgText = svgText.replace(pathData, `M${Mpath[1] || ""}`);
                    }
                    // 创建 Blob 对象
                    const blob = new Blob([svgText], { type: 'image/svg+xml' });
                    // 创建临时 URL 并设置给 img.src
                    const url = URL.createObjectURL(blob);

                    this.setSrc(url, () => {
                        const { width, height } = this.getElement();
                        const maxSide = Math.max(width, height);
                        const scale = 4096 / maxSide;
                        (this as fabric.Image).set({
                            originX: "left",
                            originY: "top",
                            left: (4096 - (width * scale)) / 2,
                            top: (4096 - (height * scale)) / 2,
                            scaleX: scale,
                            scaleY: scale,
                        });
                        this.dirty = false;
                        resolve();
                    }, { crossOrigin: "anonymous" });
                });
        });
    }

    objectCaching = false;

    // 矩形遮罩
    mark_x = 0;
    mark_y = 0;
    mark_width = 4096;
    mark_height = 4096;

    // 裁剪矩形遮罩
    clip_mark_x = 0;
    clip_mark_y = 0;
    clip_mark_width = 4096;
    clip_mark_height = 4096;

    // 缓存(导出生产文件用的)
    cacheCanvas = (() => {
        const cacheCanvas = document.createElement("canvas");
        cacheCanvas.width = 4096;
        cacheCanvas.height = 4096;
        return cacheCanvas;
    })();

    //在页面上用的
    miniCacheCanvas = (() => {
        const miniCacheCanvas = document.createElement("canvas");
        miniCacheCanvas.width = 1024;
        miniCacheCanvas.height = 1024;
        return miniCacheCanvas;
    })();

    // 设置矩形遮罩
    setRectMark(x: number, y: number, width: number, height: number) {
        this.mark_x = x * 4096;
        this.mark_y = y * 4096;
        this.mark_width = width * 4096;
        this.mark_height = height * 4096;
        this.dirty = false;
    }

    // 设置矩形的遮罩的裁剪
    setClipRectMark(x: number, y: number, width: number, height: number) {
        this.clip_mark_x = x * 4096;
        this.clip_mark_y = y * 4096;
        this.clip_mark_width = width * 4096;
        this.clip_mark_height = height * 4096;
        this.dirty = false;
    }

    //过滤目标canvas
    filter(ctx: CanvasRenderingContext2D, sideLength: number = 4096, ratio: number = window.devicePixelRatio): void {
        const cacheCtx = this.cacheCanvas.getContext("2d")!;
        cacheCtx.save();
        cacheCtx.globalCompositeOperation = "source-over";
        cacheCtx.resetTransform();
        cacheCtx.fillStyle = "#ffffff";
        cacheCtx.globalAlpha = 1;
        cacheCtx.clearRect(0, 0, 4096, 4096);
        cacheCtx.fillRect(0, 0, 4096, 4096);
        cacheCtx.restore();

        cacheCtx.setTransform(this.scaleX!, 0, 0, this.scaleY!, 2048, 2048);
        cacheCtx.globalCompositeOperation = "xor";
        super.drawObject(cacheCtx);

        cacheCtx.save();
        cacheCtx.globalCompositeOperation = "source-over";
        cacheCtx.resetTransform();
        cacheCtx.fillStyle = "#ffffff";
        cacheCtx.globalAlpha = 1;
        cacheCtx.fillRect(0, 0, 4096, this.mark_y / this.sideLength);
        cacheCtx.fillRect(0, 0, this.mark_x / this.sideLength, 4096);
        cacheCtx.fillRect((this.mark_x + this.mark_width) / this.sideLength, 0, 4096 - ((this.mark_x - this.mark_width) / this.sideLength), 4096);
        cacheCtx.fillRect(0, (this.mark_y + this.mark_height) / this.sideLength, 4096, 4096 - ((this.mark_y - this.mark_height) / this.sideLength));
        cacheCtx.fillRect(this.clip_mark_x / this.sideLength, this.clip_mark_y / this.sideLength, this.clip_mark_width / this.sideLength, this.clip_mark_height / this.sideLength);
        cacheCtx.restore();

        ctx.save();
        ctx.setTransform(1, 0, 0, 1, 0, 0);
        ctx.globalCompositeOperation = "destination-out";
        ctx.globalAlpha = 1;
        ctx.drawImage(this.cacheCanvas, 0, 0, 4096, 4096, 0, 0, sideLength * ratio, sideLength * ratio);
        ctx.restore();
    }

    // 裁剪目标canvas, 去掉轮廓和绘制区域的像素点
    clip(ctx: CanvasRenderingContext2D, sideLength: number = 4096, ratio: number = window.devicePixelRatio): void {
        const cacheCtx = this.cacheCanvas.getContext("2d")!;
        cacheCtx.save();
        cacheCtx.globalCompositeOperation = "source-over";
        cacheCtx.resetTransform();
        // cacheCtx.fillStyle = "#ffffff";
        // cacheCtx.globalAlpha = 1;
        // cacheCtx.clearRect(0, 0, 4096, 4096);
        // cacheCtx.fillRect(0, 0, 4096, 4096);
        cacheCtx.restore();

        cacheCtx.setTransform(this.scaleX!, 0, 0, this.scaleY!, 2048, 2048);
        cacheCtx.globalCompositeOperation = "xor";
        // super.drawObject(cacheCtx);

        cacheCtx.save();
        cacheCtx.globalCompositeOperation = "source-over";
        cacheCtx.resetTransform();
        cacheCtx.fillStyle = "#ff00ff";
        cacheCtx.globalAlpha = 1;
        cacheCtx.fillRect(0, 0, 4096, this.mark_y / this.sideLength);
        cacheCtx.fillRect(0, 0, this.mark_x / this.sideLength, 4096);
        cacheCtx.fillRect((this.mark_x + this.mark_width) / this.sideLength, 0, 4096 - ((this.mark_x - this.mark_width) / this.sideLength), 4096);
        cacheCtx.fillRect(0, (this.mark_y + this.mark_height) / this.sideLength, 4096, 4096 - ((this.mark_y - this.mark_height) / this.sideLength));
        cacheCtx.fillRect(this.clip_mark_x / this.sideLength, this.clip_mark_y / this.sideLength, this.clip_mark_width / this.sideLength, this.clip_mark_height / this.sideLength);
        cacheCtx.restore();

        ctx.save();
        ctx.setTransform(1, 0, 0, 1, 0, 0);
        ctx.globalCompositeOperation = "destination-out";
        ctx.globalAlpha = 1;
        ctx.drawImage(this.cacheCanvas, 0, 0, 4096, 4096, 0, 0, sideLength * ratio, sideLength * ratio);
        ctx.restore();
    }

    // 只裁剪轮廓,不包含局部绘制区域
    clipOutLine(ctx: CanvasRenderingContext2D, sideLength: number = 1024, ratio: number = window.devicePixelRatio, color: string = "#f5f5f5", opacity: number = 1): void {
        const miniCacheCtx = this.miniCacheCanvas.getContext("2d")!;
        miniCacheCtx.save();
        miniCacheCtx.globalCompositeOperation = "source-over";
        miniCacheCtx.resetTransform();
        miniCacheCtx.fillStyle = color;// "#f5f5f5";
        miniCacheCtx.globalAlpha = 1;
        miniCacheCtx.clearRect(0, 0, 1024, 1024);
        miniCacheCtx.fillRect(0, 0, 1024, 1024);
        // miniCacheCtx.clearRect(this.clip_mark_x * 1024, this.clip_mark_y * 1024, this.clip_mark_width * 1024, this.clip_mark_height * 1024);
        miniCacheCtx.restore();

        miniCacheCtx.setTransform(this.scaleX! * 0.25, 0, 0, this.scaleY! * 0.25, 512, 512);
        miniCacheCtx.globalCompositeOperation = "xor";
        super.drawObject(miniCacheCtx);

        ctx.save();
        ctx.setTransform(1, 0, 0, 1, 0, 0);
        ctx.globalAlpha = opacity;
        ctx.drawImage(this.miniCacheCanvas, 0, 0, sideLength * ratio, sideLength * ratio);
        ctx.restore();
    }

    // 绘制一个黑色的遮罩层,包括轮廓 和 绘制区域
    drawObject(ctx: CanvasRenderingContext2D): void {
        const cacheCtx = this.cacheCanvas.getContext("2d")!;
        cacheCtx.save();
        cacheCtx.globalCompositeOperation = "source-over";
        cacheCtx.resetTransform();
        cacheCtx.fillStyle = "#ffffff";
        cacheCtx.globalAlpha = 1;
        cacheCtx.clearRect(0, 0, 4096, 4096);
        cacheCtx.fillRect(0, 0, 4096, 4096);
        cacheCtx.restore();

        cacheCtx.setTransform(this.scaleX!, 0, 0, this.scaleY!, 2048, 2048);
        cacheCtx.globalCompositeOperation = "xor";
        super.drawObject(cacheCtx);
        //如果是局部打印的话 就绘制一个红白相间的打印框
        if (this.mark_x > 0 && this.mark_y > 0) {
            cacheCtx.save();
            cacheCtx.globalCompositeOperation = "source-over";
            cacheCtx.resetTransform();
            cacheCtx.strokeStyle = "#cccccc";
            cacheCtx.lineWidth = 16;
            cacheCtx.globalAlpha = 1;
            cacheCtx.setLineDash([54, 46]);
            cacheCtx.beginPath();
            cacheCtx.moveTo((this.mark_x - 9) / this.sideLength, (this.mark_y - 9) / this.sideLength);
            cacheCtx.lineTo((this.mark_x + this.mark_width + 9) / this.sideLength, (this.mark_y - 9) / this.sideLength);
            cacheCtx.lineTo((this.mark_x + this.mark_width + 9) / this.sideLength, (this.mark_y + this.mark_height + 9) / this.sideLength);
            cacheCtx.lineTo((this.mark_x - 9) / this.sideLength, (this.mark_y + this.mark_height + 9) / this.sideLength);
            cacheCtx.closePath();
            cacheCtx.stroke();
            cacheCtx.restore();

            cacheCtx.save();
            cacheCtx.globalCompositeOperation = "source-over";
            cacheCtx.resetTransform();
            cacheCtx.strokeStyle = "#ff0000";
            cacheCtx.lineWidth = 8;
            cacheCtx.globalAlpha = 1;
            cacheCtx.setLineDash([50, 50]);
            cacheCtx.beginPath();
            cacheCtx.moveTo((this.mark_x - 9) / this.sideLength, (this.mark_y - 9) / this.sideLength);
            cacheCtx.lineTo((this.mark_x + this.mark_width + 9) / this.sideLength, (this.mark_y - 9) / this.sideLength);
            cacheCtx.lineTo((this.mark_x + this.mark_width + 9) / this.sideLength, (this.mark_y + this.mark_height + 9) / this.sideLength);
            cacheCtx.lineTo((this.mark_x - 9) / this.sideLength, (this.mark_y + this.mark_height + 9) / this.sideLength);
            cacheCtx.closePath();
            cacheCtx.stroke();
            cacheCtx.restore();

            cacheCtx.save();
            cacheCtx.globalCompositeOperation = "source-over";
            cacheCtx.resetTransform();
            cacheCtx.strokeStyle = "#cccccc";
            cacheCtx.lineWidth = 16;
            cacheCtx.globalAlpha = 1;
            cacheCtx.setLineDash([54, 46]);
            cacheCtx.beginPath();
            cacheCtx.moveTo((this.clip_mark_x + 9) / this.sideLength, (this.clip_mark_y + 9) / this.sideLength);
            cacheCtx.lineTo((this.clip_mark_x + this.clip_mark_width - 9) / this.sideLength, (this.clip_mark_y + 9) / this.sideLength);
            cacheCtx.lineTo((this.clip_mark_x + this.clip_mark_width - 9) / this.sideLength, (this.clip_mark_y + this.clip_mark_height - 9) / this.sideLength);
            cacheCtx.lineTo((this.clip_mark_x + 9) / this.sideLength, (this.clip_mark_y + this.clip_mark_height - 9) / this.sideLength);
            cacheCtx.closePath();
            cacheCtx.stroke();
            cacheCtx.restore();

            cacheCtx.save();
            cacheCtx.globalCompositeOperation = "source-over";
            cacheCtx.resetTransform();
            cacheCtx.strokeStyle = "#ff0000";
            cacheCtx.lineWidth = 8;
            cacheCtx.globalAlpha = 1;
            cacheCtx.setLineDash([50, 50]);
            cacheCtx.beginPath();
            cacheCtx.moveTo((this.clip_mark_x + 9) / this.sideLength, (this.clip_mark_y + 9) / this.sideLength);
            cacheCtx.lineTo((this.clip_mark_x + this.clip_mark_width - 9) / this.sideLength, (this.clip_mark_y + 9) / this.sideLength);
            cacheCtx.lineTo((this.clip_mark_x + this.clip_mark_width - 9) / this.sideLength, (this.clip_mark_y + this.clip_mark_height - 9) / this.sideLength);
            cacheCtx.lineTo((this.clip_mark_x + 9) / this.sideLength, (this.clip_mark_y + this.clip_mark_height - 9) / this.sideLength);
            cacheCtx.closePath();
            cacheCtx.stroke();
            cacheCtx.restore();

            ctx.save();
            ctx.setTransform(1, 0, 0, 1, 0, 0);
            ctx.globalAlpha = 1;
            ctx.drawImage(this.cacheCanvas, 0, 0, 1024, 1024);
            ctx.restore();

        }

    }

}